package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.openea.perpartner.meily.util.UserContext;
import cn.openea.perpartner.meily.web.convert.AttrDataConvert;
import cn.openea.perpartner.meily.web.entity.*;
import cn.openea.perpartner.meily.web.entity.dto.*;
import cn.openea.perpartner.meily.web.mapper.*;
import cn.openea.perpartner.meily.web.service.IShopProductService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Weird077
 * @description TODO
 * @date 2023-04-17 16:12
 */
@Slf4j
@Service
public class ShopProductServiceImpl implements IShopProductService {
    @Autowired
    private ShopBaseProductTypeMapper baseProductTypeMapper;
    @Autowired
    private ShopBaseProductTypeAttributeMapper baseProductTypeAttributeMapper;
    @Autowired
    private ShopProductAttributeMapper productAttributeMapper;
    @Autowired
    private ShopBaseSpecMapper baseSpecMapper;
    @Autowired
    private ShopBaseSpecValueMapper baseSpecValueMapper;
    @Autowired
    private ShopProductSpecMapper productSpecMapper;
    @Autowired
    private ShopProductSpecValueMapper productSpecValueMapper;

    @Override
    public List<ShopBaseProductType> productTypeData() {
        return baseProductTypeMapper.selectList(Wrappers.emptyWrapper());
    }

    @Override
    public ShopProductSpec specCreate(ShopProductSpec spec) {
        spec.setCreateUser(UserContext.getUserId());
        spec.setUpdateUser(UserContext.getUserId());
        return productSpecMapper.insert(spec) > 0 ? spec : null;
    }

    @Override
    public int specDelete(Long id) {
        return productSpecMapper.deleteById(id);
    }

    @Override
    public ShopProductSpecValue specValueCreate(ShopProductSpecValue specValue) {
        specValue.setCreateUser(UserContext.getUserId());
        specValue.setUpdateUser(UserContext.getUserId());
        return productSpecValueMapper.insert(specValue) > 0 ? specValue : null;
    }

    @Override
    public int specValueDelete(Long id) {
        return productSpecValueMapper.deleteById(id);
    }

    @Override
    public AttrSpecDto baseAttrSpecData(String productTypeId) {
        // 1. 查询属性
        List<AttrData> attributeList = baseProductTypeAttributeMapper.selectJoinList(AttrData.class,
                new MPJLambdaWrapper<ShopBaseProductTypeAttribute>()
                        .select(ShopBaseProductTypeAttribute::getId, ShopBaseProductTypeAttribute::getTitle)
                        .select(ShopBaseProductTypeAttribute::getType, ShopBaseProductTypeAttribute::getMerchantId)
                        .selectAs(ShopBaseProductTypeAttribute::getValue, "options")
                        .eq(ShopBaseProductTypeAttribute::getProductTypeId, productTypeId));
        List<AttrDataDto> attrDataDtoList = attributeList.stream().map(AttrDataConvert.INSTANCE::toDto).collect(Collectors.toList());
        //2. 查询规格
        List<SpecData> specList = baseSpecMapper.selectJoinList(SpecData.class,
                new MPJLambdaWrapper<>(ShopBaseSpec.class)
                        .select(ShopBaseSpec::getId, ShopBaseSpec::getTitle)
                        .in(ShopBaseSpec::getMerchantId, attributeList.stream()
                                .map(AttrData::getMerchantId)
                                .distinct().collect(Collectors.toList())));

        //3. 查询规格值
        specList.forEach(specData -> {
            List<ShopBaseSpecValue> specValueList = baseSpecValueMapper.selectList(new MPJLambdaWrapper<>(ShopBaseSpecValue.class)
                    .select(ShopBaseSpecValue::getId, ShopBaseSpecValue::getTitle)
                    .eq(ShopBaseSpecValue::getSpecId, specData.getId()));
            specData.setOptions(specValueList.stream().map(specValue -> {
                JSONObject json = new JSONObject();
                json.put("id", specValue.getId());
                json.put("title", specValue.getTitle());
                return json;
            }).collect(Collectors.toList()));
            specData.setValue(Collections.emptyList());
        });
        return AttrSpecDto.builder()
                .attribute(attrDataDtoList)
                .spec(specList)
                .build();
    }

    public AttrSpecDto productAttrSpecData(String productTypeId, String productId) {
        // 1. 查询属性
        List<AttrData> attributeList = baseProductTypeAttributeMapper.selectJoinList(AttrData.class, new MPJLambdaWrapper<ShopBaseProductTypeAttribute>()
                .select(ShopBaseProductTypeAttribute::getId, ShopBaseProductTypeAttribute::getTitle)
                .select(ShopBaseProductTypeAttribute::getType)
                .selectAs(ShopBaseProductTypeAttribute::getValue, "options")
                .select(ShopProductAttribute::getValue)
                .leftJoin(ShopProductAttribute.class, ShopProductAttribute::getProductTypeAttributeId, ShopBaseProductTypeAttribute::getId)
                .eq(ShopBaseProductTypeAttribute::getProductTypeId, productTypeId)
                .eq(ShopProductAttribute::getProductId, productId));
        //2.取出商品属性类型
        HashMap<Object, Object> typeMap = new HashMap<>();
        attributeList.stream().forEach(attrData -> {
            typeMap.put(attrData.getId(), attrData.getType());
        });
        //3. 查询商品规格
        List<ShopProductSpec> productSpecList = productSpecMapper.selectList(Wrappers.<ShopProductSpec>lambdaQuery()
                .eq(ShopProductSpec::getProductId, productId)
                .orderByAsc(ShopProductSpec::getSort));
        List<SpecData> specList = new ArrayList<>();
        productSpecList.forEach(productSpec -> {
            specList.add(SpecData.builder()
                    .id(productSpec.getSpecId())
                    .title(productSpec.getTitle()).build());
        });

        //4. 查询商品规格值
        specList.forEach(specData -> {
            //4.1 取系统规格值
            List<ShopBaseSpecValue> specValueList = baseSpecValueMapper.selectList(new MPJLambdaWrapper<>(ShopBaseSpecValue.class)
                    .select(ShopBaseSpecValue::getId, ShopBaseSpecValue::getTitle)
                    .eq(ShopBaseSpecValue::getSpecId, specData.getId()));
            specData.setOptions(specValueList.stream().map(specValue -> {
                JSONObject json = new JSONObject();
                json.put("id", specValue.getId());
                json.put("title", specValue.getTitle());
                return json;
            }).collect(Collectors.toList()));
            //4.2 取商品规格值
            List<String> specValueIdList = productSpecValueMapper.selectList(new MPJLambdaWrapper<>(ShopProductSpecValue.class)
                            .select(ShopProductSpecValue::getSpecValueId)
                            .eq(ShopProductSpecValue::getProductId, productId))
                    .stream().map(ShopProductSpecValue::getSpecValueId).collect(Collectors.toList());
            //4.3 若商品规格值不在系统规格值中，则移除
            List<String> optionIdList = specData.getOptions().stream().map(json -> json.getString("id")).collect(Collectors.toList());
            specValueIdList.removeIf(specValueId -> !optionIdList.contains(specValueId));
            specData.setValue(specValueIdList);
        });
        return AttrSpecDto.builder()
                .attribute(attributeList.stream().map(AttrDataConvert.INSTANCE::toDto).collect(Collectors.toList()))
                .spec(specList)
                .build();
    }

    @Override
    public AttrSpecDto attrSpecData(String productTypeId, String productId) {
        if (StrUtil.isBlank(productId)) {
            return baseAttrSpecData(productTypeId);
        }
        return productAttrSpecData(productTypeId, productId);
    }

    @Override
    public ShopBaseProductType productTypeCreate(ShopBaseProductType productType) {
        productType.setCreateUser(UserContext.getUserId());
        productType.setUpdateUser(UserContext.getUserId());
        return baseProductTypeMapper.insert(productType) > 0 ? productType : null;
    }

    @Override
    public ShopBaseProductTypeAttribute productTypeValueCreate(ShopBaseProductTypeAttribute productTypeAttribute) {
        productTypeAttribute.setCreateUser(UserContext.getUserId());
        productTypeAttribute.setUpdateUser(UserContext.getUserId());
        return baseProductTypeAttributeMapper.insert(productTypeAttribute) > 0 ? productTypeAttribute : null;
    }

    @Override
    public int productTypeDelete(Long id) {
        return baseProductTypeMapper.deleteById(id);
    }

    @Override
    public int productTypeValueDelete(Long id) {
        return baseProductTypeAttributeMapper.deleteById(id);
    }

    @Override
    public ShopBaseSpec baseSpecCreate(ShopBaseSpec spec) {
        spec.setCreateUser(UserContext.getUserId());
        spec.setUpdateUser(UserContext.getUserId());
        return baseSpecMapper.insert(spec) > 0 ? spec : null;
    }

    @Override
    public int baseSpecDelete(Long id) {
        return baseSpecMapper.deleteById(id);
    }

    @Override
    public ShopBaseSpecValue baseSpecValueCreate(ShopBaseSpecValue specValue) {
        specValue.setCreateUser(UserContext.getUserId());
        specValue.setUpdateUser(UserContext.getUserId());
        return baseSpecValueMapper.insert(specValue) > 0 ? specValue : null;
    }

    @Override
    public int baseSpecValueDelete(Long id) {
        return baseSpecValueMapper.deleteById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int productAttrCreate(List<ShopProductAttribute> productAttributeList) {
        int count = 0;
        for (ShopProductAttribute attribute : productAttributeList) {
            LambdaQueryWrapper<ShopProductAttribute> wrapper = Wrappers.lambdaQuery(ShopProductAttribute.class)
                    .eq(ShopProductAttribute::getProductId, attribute.getProductId())
                    .eq(ShopProductAttribute::getProductTypeAttributeId, attribute.getProductTypeAttributeId());
            ShopProductAttribute productAttribute = productAttributeMapper.selectOne(wrapper);
            if (BeanUtil.isEmpty(productAttribute)) {
                attribute.setCreateUser(UserContext.getUserId());
                attribute.setUpdateUser(UserContext.getUserId());
                count = productAttributeMapper.insert(attribute);
            } else {
                attribute.setId(productAttribute.getId());
                attribute.setUpdateUser(UserContext.getUserId());
                count = productAttributeMapper.updateById(attribute);
            }
        }
        return count;
    }
}
